﻿using Application.Job;
using Application.Utils;
using Microsoft.OpenApi.Models;
using Quartz;
using System.Reflection;
using System.Runtime.Loader;
using System.Text.RegularExpressions;

namespace Web
{
    public static class ServiceCollectionExtension
    {
        #region 定时任务
        public static IServiceCollection AddQuartzInit(this IServiceCollection services)
        {
            var context = services.BuildServiceProvider().GetRequiredService<JobManagerDbContext>();
            #region 取DB任务列表，并触发任务
            services.AddQuartz(config =>
            {

                #region 更新服务状态
                var jobKey = new JobKey("ServerStatusJob", JobGroupName.System);
                config.AddJob<ServerStatusJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartNow()
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0/10 * * * * ?");
                });
                #endregion

                #region 分配服务
                jobKey = new JobKey("AssignJob", JobGroupName.System);
                config.AddJob<AssignJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(10)))
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0/20 * * * * ?");
                });
                #endregion

                #region 操作任务
                jobKey = new JobKey("OperationQueueJob", JobGroupName.System);
                config.AddJob<OperationQueueJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(10)))
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0/3 * * * * ?");
                });
                #endregion

                #region 更新job状态
                jobKey = new JobKey(nameof(TaskStatusJob), JobGroupName.System);
                config.AddJob<TaskStatusJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartNow()
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0 0/1 * * * ?");
                });
                #endregion

                #region 定期清理执行日志
                jobKey = new JobKey("CleanupLogsJob", JobGroupName.System);
                config.AddJob<CleanupLogsJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(10)))
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0 0 0/2 * * ?");//每隔2h检测一次
                });
                #endregion

                #region 通知
                jobKey = new JobKey("NoticeJob", JobGroupName.System);
                config.AddJob<NoticeJob>(jobCfg => { jobCfg.WithIdentity(jobKey); });
                config.AddTrigger(trigger =>
                {
                    trigger
                        .ForJob(jobKey)
                        .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(10)))
                        .WithIdentity(jobKey.Name, jobKey.Group)
                        .WithCronSchedule("0 */1 * * * ?");
                });
                #endregion

            });
            #endregion

            services.AddQuartzHostedService(opt =>
            {
                opt.WaitForJobsToComplete = true;//安全退出程序
            });
            return services;
        }
        #endregion

        #region AddSwagger
        public static void AddSwaggerWithAuth(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                //Bearer 的scheme定义
                var securityScheme = new OpenApiSecurityScheme()
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    //参数添加在头部
                    In = ParameterLocation.Header,
                    //使用Authorize头部
                    Type = SecuritySchemeType.Http,
                    //内容为以 bearer开头
                    Scheme = "bearer",
                    BearerFormat = "JWT"
                };

                //把所有方法配置为增加bearer头部信息
                var securityRequirement = new OpenApiSecurityRequirement
                    {
                      {
                       new OpenApiSecurityScheme
                       {
                           Reference = new OpenApiReference
                           {
                               Type = ReferenceType.SecurityScheme,
                               Id = "bearerAuth"
                           }
                       },
                       new string[] {}
                      }
                    };
                //注册到swagger中
                c.AddSecurityDefinition("bearerAuth", securityScheme);
                c.AddSecurityRequirement(securityRequirement);
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                //c.IncludeXmlComments($"{AppDomain.CurrentDomain.BaseDirectory}/{AppDomain.CurrentDomain.FriendlyName}.xml");
            });
        }
        public static void AddSwagger(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                //注册到swagger中
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                c.IncludeXmlComments($"{AppDomain.CurrentDomain.BaseDirectory}/{AppDomain.CurrentDomain.FriendlyName}.xml");
            });
        }
        #endregion

        #region 批量注册服务到IOC
        /// <summary>
        /// 批量注册服务到IOC  约定当前程序集xx.Service.xxService
        /// </summary>
        /// <param name="services"></param>
        public static IServiceCollection AddScopedService0(this IServiceCollection services)
        {
            var assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
            var types = assembly.GetTypes();
            var list = types.Where(u => u.IsClass && !u.IsAbstract && !u.IsGenericType && new Regex(@$"{assemblyName}[.]Service[.].+Service$").IsMatch(u.FullName)).ToList();
            foreach (var item in list)
            {
                services.AddScoped(item);
            }
            services.AddScoped<Accessor>();
            return services;
        }
        public static IServiceCollection AddScopedServices(this IServiceCollection services)
        {
            var typesFromAssemblies = typeof(JobService).Assembly.GetTypes()
                .Where(type => type.IsClass && !type.IsAbstract && !type.IsGenericType);

            foreach (var type in typesFromAssemblies)
            {
                var interfaceType = type.GetInterfaces().FirstOrDefault(i => i.Name == $"I{type.Name}");
                if (interfaceType != null)
                {
                    services.AddScoped(interfaceType, type);
                }
            }
            services.AddScoped<Accessor>();
            return services;
        }
        #endregion
    }
}
